[org 0x1000]
dw 0x55aa
global _start_setup
_start_setup:
    mov si,loading
    call print
    call detect_memory

detect_memory:
    xor ebx,ebx;将ebx置为0

    ;es:di 结构体的缓存位置
    mov ax,0
    mov es,ax
    mov edi,ards_buffer

    mov edx,0x534d4150;固定签名

    .next:
        ;子功能号
        mov eax,0xe820
        ;ards 结构的大小(字节)
        mov ecx,20
        ;调用0x15系统调用
        int 0x15

        ;如果CF置位就说明出错
        jc error

        ; 将缓存指针指向下一个结构体
        add di,cx

        ; 将结构体数量加一
        inc word [ards_count]

        cmp ebx,0
        jnz .next

    mov si,detecting
    call print

    jmp prepare_protected_mode

print:
    mov ah,0x0e
    .next:
        mov al,[si]
        cmp al,0
        jz .done
        int 0x10
        inc si
        jmp .next
    .done:
        ret

loading:
    db "ChenPuchu see,'This os setup is run and it is loading os-kernel now'",10,13,0
detecting:
    db "ChenPuchu see,'The Memory Detectiong Success'",10,13,0

error:
    mov si,.msg
    call print
    hlt;让cpu停止
    jmp $
    .msg db "ChenPuchu's setup error",10,13,0

prepare_protected_mode:
    ;保护模式
    cli;关中断

    ;打开 A20 线
    in al,0x92
    or al,0b10
    out 0x92,al

    ;加载gdt
    lgdt [gdt_ptr]

    ;启动保护模式
    mov eax,cr0
    or eax,1
    mov cr0,eax

    ;用jmp来刷新缓存，启动保护模式
    jmp dword code_selector:protect_mode

[bits 32]
protect_mode:
    mov ax,data_selector
    mov ds,ax
    mov es,ax
    mov fs,ax
    mov gs,ax
    mov ss,ax;初始段寄存器

    mov esp,0x10000;修改栈顶s


    ;读取硬盘
    mov edi,0x10000; 读取到的目标内存
    mov ecx,10; 起始扇区
    mov bl,500; 扇区数量

    call read_disk

    jmp dword code_selector:0x10000

    ud2;表示出错
    jmp $


read_disk:
    ; 设置读写扇区的数量
    mov dx,0x1f2
    mov al,bl
    out dx,al

    inc dx
    mov al,cl;起始扇区的前八位
    out dx,al

    inc dx
    shr ecx,8
    mov al,cl;起始扇区的中八位
    out dx,al

    inc dx
    shr ecx,8
    mov al,cl;起始扇区的高八位
    out dx,al

    inc dx
    shr ecx,8
    and cl,0b1111;将高四位设为0

    mov al,0b1110_0000
    or al,cl
    out dx,al

    inc dx
    mov al,0x20; 表示读取硬盘
    out dx,al

    xor ecx,ecx;清空ecx
    mov cl,bl;得到读写扇区的数量

    .read:
        push cx
        call .waits;等待数据准备完毕
        call .reads;读取扇区
        pop cx
        loop .read
    ret

.waits:
    mov dx,0x1f7
    .check:
        in al,dx
        jmp $+2;加上延迟
        jmp $+2
        jmp $+2
        and al,0b1000_1000
        cmp al,0b0000_1000
        jnz .check
    ret

.reads:
    mov dx,0x1f0
    mov cx,256;一个扇区256字
    .readw:
        in ax,dx
        jmp $+2
        jmp $+2
        jmp $+2
        mov [edi],ax
        add edi,2
        loop .readw
    ret

code_selector equ (1<<3)
data_selector equ (2<<3)

memory_base equ 0;内存开始的位置，基地址
memory_limit equ ((1024*1024*1024*4)/(1024*4)-1);内存界限 4G / 4K - 1

gdt_ptr:
    dw (gdt_end - gdt_base) - 1
    dd gdt_base
gdt_base:
    dd 0,0; NULL 描述符
gdt_code:
    dw memory_limit & 0xffff;段界限 0 ~ 15 位
    dw memory_base & 0xffff;基地址  0 ~ 15 位
    db (memory_base>>16) & 0xffff;基地址  16 ~ 23 位
    db 0b_1_00_1_1_0_1_0; 存在 - dlp 0 - S _ 代码 - 非依从 - 可读 - 没有被访问过
    db 0b1_1_0_0_0000 | (memory_limit >> 16);4k = 32位 - 不是64位 - 段界限 16 ~ 19
    db (memory_base >>24) & 0xff;基地址 24 ~ 31 位
gdt_data:
    dw memory_limit & 0xffff;段界限 0 ~ 15 位
    dw memory_base & 0xffff;基地址  0 ~ 15 位
    db (memory_base>>16) & 0xffff;基地址  16 ~ 23 位
    db 0b_1_00_1_0_0_1_0; 存在 - dlp 0 - S _ 数据 - 向上 - 可写 - 没有被访问过
    db 0b1_1_0_0_0000 | (memory_limit >> 16);4k = 32位 - 不是64位 - 段界限 16 ~ 19
    db (memory_base >>24) & 0xff;基地址 24 ~ 31 位
gdt_end:

ards_count:
    dw 0
ards_buffer:
